跳到主要内容

【教程】从零开始搭建 k3s 集群

k3s 高可用集群封面图

提示:本教程基于 Linux + fish shell 编写,个别命令语法与 Bash 略有差异。请结合自己的系统环境调整命令。

引言

众所周知,k3s 是由 Rancher Labs 开发的轻量级 Kubernetes 发行版,也是目前最流行的 K8s 轻量化方案。

相较于传统运维方式(1Panel/宝塔/SSH 等),k3s 的学习曲线更陡峭,需要理解更多容器编排概念。但一旦掌握,你将获得:

k3s 的核心优势

  • 轻量高效 - 单个二进制文件,内存占用 < 512MB,完美适配低配 VPS
  • 生产就绪 - 完全兼容 Kubernetes API,可平滑迁移到标准 K8s
  • 声明式运维 - 用 YAML 描述期望状态,系统自动维护
  • 高可用保障 - 自动故障恢复 + 多节点负载均衡
  • 开箱即用 - 内置网络、存储、Ingress 等核心组件

通过 k3s,我们可以将多台廉价 VPS 整合为企业级高可用集群,实现传统运维难以达到的自动化水平。

目标读者与准备

适合人群

  • 有一定 Linux 基础的开发者
  • 希望从传统运维过渡到容器编排
  • 想搭建个人高可用服务的技术爱好者

前置知识

  • 熟悉 Linux 命令行操作
  • 了解 Docker 容器基础
  • 具备基本的网络知识(SSH、防火墙)

学习收获

完成本教程后,你将掌握:

  1. 使用 k3sup 快速部署 k3s 集群
  2. 理解 k3s 核心组件(API Server、etcd、kubelet 等)的作用
  3. 替换默认组件优化性能(Cilium CNI、Nginx Ingress 等)
  4. 部署第一个应用并配置外部访问
  5. 基本的集群运维和故障排查技巧

部署规划

k3s 默认安装了一套精简组件,为了满足生产级诉求,我们需要提前规划哪些模块要保留或替换。下表展示了推荐的取舍策略:

组件类型k3s 默认组件替换组件替换理由k3sup 禁用参数
容器运行时containerd-保持默认即可-
数据存储SQLite / etcd-单节点用 SQLite,集群用 etcd-
Ingress ControllerTraefikNginx Ingress / 其他团队更熟悉、功能需求不同--disable traefik
LoadBalancerService LB (Klipper-lb)不想部署懒得管负载均衡,直接买 cloudflare--disable servicelb
DNSCoreDNS-保持默认即可-
Storage ClassLocal-path-provisionerLonghorn分布式存储、高可用、备份能力--disable local-storage
CNIFlannelCiliumeBPF 性能、网络策略、可观测性--flannel-backend=none --disable-network-policy

k3s 默认组件与替换方案对比表

环境准备

必备工具

首先,确保 k3sup、kubectl、Helm 等工具已正确安装(可参考各自 GitHub 项目提供的安装说明):

k3sup version
kubectl version
helm version

如图所示:

工具安装版本检查截图

服务器要求

准备至少三台云服务器(示例环境使用 Ubuntu 24.04),作为最小化三节点高可用控制平面(推荐配置 ≥ 4C4G)。提前记录各节点 IP、确认 SSH 公钥已分发,并知晓本地私钥路径,后续步骤会用到。

部署初始控制平面

使用 k3sup 部署初始控制节点:

k3sup install \
--ip 初始节点 IP \
--user root \
--ssh-key 密钥位置 \
--k3s-channel latest \
--cluster \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"

如图所示: k3sup 安装初始控制节点输出

安装完成后,k3sup 会自动将 kubeconfig 复制到当前目录。虽然可以直接使用这份配置,但更加稳健的做法是与现有配置文件合并。

合并 kubeconfig

  1. 备份当前的 kubeconfig(默认位于 ~/.kube/config):
cp ~/.kube/config ~/.kube/config.backup

fish shell(仅供参考):

cp $KUBECONFIG {$KUBECONFIG}.backup
  1. 将新旧 kubeconfig 合并为一份扁平文件:
KUBECONFIG=~/.kube/config:./kubeconfig kubectl config view --flatten > ~/.kube/config.new

fish shell(仅供参考):

KUBECONFIG=$KUBECONFIG:./kubeconfig kubectl config view --flatten > kubeconfig-merged.yaml
  1. 检查新文件内容无误后覆盖旧配置:
mv ~/.kube/config.new ~/.kube/config

fish shell

mv ./kubeconfig-merged.yaml $KUBECONFIG
  1. 验证新上下文是否生效:
kubectl config get-contexts
kubectl config use-context default

安装 Cilium(替代 Flannel)

安装 k3s 时我们禁用了默认 CNI(Flannel),因此节点暂时无法互通。按计划部署 Cilium 以提供网络与网络策略能力。

使用 Helm 安装 Cilium:

# 添加 Cilium Helm 仓库
helm repo add cilium https://helm.cilium.io/

# 更新 Helm 仓库
helm repo update

# 安装 Cilium CNI(单副本,默认模式)
helm install cilium cilium/cilium \
--namespace kube-system \
--set operator.replicas=1 \
--set ipam.mode=kubernetes

如果集群已经禁用 kube-proxy,可额外添加 --set kubeProxyReplacement=strict。本教程保持默认值以兼容更多场景。

执行完成后可以看到: Helm 安装 Cilium 终端输出 Cilium Pod 与节点状态检查输出

等待 Cilium 组件启动完成:

# 查看 Cilium 相关 Pod 状态
kubectl get pods -n kube-system -l k8s-app=cilium

# 查看节点状态(应该从 NotReady 变为 Ready)
kubectl get nodes

kubectl 控制平面节点已就绪截图

节点切换到 Cilium 后应当从 NotReady 变为 Ready。接下来使用 k3sup 加入另外两个控制节点。

扩容控制平面

为了实现高可用,我们需要至少 3 个控制节点。使用以下命令加入第二个控制节点:

k3sup join \
--ip 第二个节点 IP \
--user root \
--ssh-key 密钥位置 \
--server-ip 初始节点 IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"

同样的方式加入第三个控制节点:

k3sup join \
--ip 第三个节点 IP \
--user root \
--ssh-key 密钥位置 \
--server-ip 初始节点 IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"

等待几分钟后检查集群状态:

kubectl get nodes

当三个控制节点均处于 Ready 状态时,控制平面即告搭建完成。

加入更多控制节点后的集群状态

安装 Nginx Ingress Controller

替换 k3s 默认的 Traefik,安装 Nginx Ingress Controller:

# 添加 Nginx Ingress Helm 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# 安装 Nginx Ingress Controller(可能需要等待很久)
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.hostPort.enabled=true \
--set controller.hostPort.ports.http=80 \
--set controller.hostPort.ports.https=443 \
--set controller.service.type=ClusterIP
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Nginx Ingress Controller 组件状态截图

安装 Longhorn 分布式存储

Longhorn 是由 Rancher 开发的云原生分布式块存储系统,提供高可用、备份、快照等企业级功能。相比 k3s 默认的 local-path-provisioner,Longhorn 支持跨节点的持久化存储。

前置依赖检查

在安装 Longhorn 之前,需要确保每个节点都安装了必要依赖;若希望通过 Ansible 批量处理,可参考后续示例:

# 在每个节点上执行(通过 SSH)
# 检查并安装 open-iscsi
apt update
apt install -y open-iscsi nfs-common

# 启动并设置开机自启
systemctl enable --now iscsid
systemctl status iscsid

如果希望使用 Ansible 批量安装依赖,可以参考以下任务片段:

---
- name: Setup K3s nodes with Longhorn dependencies and CrowdSec
hosts: k3s
become: true
vars:
crowdsec_version: "latest"

tasks:
# ============================================
# Longhorn Prerequisites
# ============================================
- name: Install Longhorn required packages
ansible.builtin.apt:
name:
- open-iscsi # iSCSI support for volume mounting
- nfs-common # NFS support for backup target
- util-linux # Provides nsenter and other utilities
- curl # For downloading and API calls
- jq # JSON processing for Longhorn CLI
state: present
update_cache: true
tags: longhorn

- name: Enable and start iscsid service
ansible.builtin.systemd:
name: iscsid
enabled: true
state: started
tags: longhorn

- name: Load iscsi_tcp kernel module
community.general.modprobe:
name: iscsi_tcp
state: present
tags: longhorn

- name: Ensure iscsi_tcp loads on boot
ansible.builtin.lineinfile:
path: /etc/modules-load.d/iscsi.conf
line: iscsi_tcp
create: true
mode: '0644'
tags: longhorn

- name: Check if multipathd is installed
ansible.builtin.command: which multipathd
register: multipathd_check
failed_when: false
changed_when: false
tags: longhorn

- name: Disable multipathd if installed (conflicts with Longhorn)
ansible.builtin.systemd:
name: multipathd
enabled: false
state: stopped
when: multipathd_check.rc == 0
tags: longhorn

部署 Longhorn

使用 Helm 安装 Longhorn:

# 添加 Longhorn Helm 仓库
helm repo add longhorn https://charts.longhorn.io
helm repo update

# 安装 Longhorn(可能需要等待较长时间),请注意这里为了节约硬盘空间,只设置了单副本,请根据需求自行调整
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.defaultDataPath="/var/lib/longhorn" \
--set persistence.defaultClass=true \
--set persistence.defaultClassReplicaCount=1

等待 Longhorn 组件启动:

# 查看 Longhorn 组件状态
kubectl get pods -n longhorn-system

# 查看 StorageClass
kubectl get storageclass

Longhorn 组件运行状态截图 Longhorn 存储类列表截图

访问 Longhorn UI(可选)

Longhorn 提供了一个 Web UI 用于管理存储卷。可以通过端口转发临时访问:

# 端口转发到本地
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8081:80

# 在浏览器访问 http://localhost:8081

完成查看后,请在终端按 Ctrl+C 停止端口转发,避免持续占用本地端口。

加入 Agent 节点

目前为止,我们搭建了一个 3 节点的高可用控制平面(control-plane)。在生产环境中,我们不希望在 control-plane 节点上运行实际的应用程序(会占用 API Server、etcd 等核心组件的资源)。

因此,我们需要加入专门用于运行工作负载(Pods)的 Agent 节点(也称为 Worker 节点)。

安装前置依赖

与 control-plane 节点一样,Agent 节点也需要满足 Longhorn 的依赖(若希望这些节点能够调度并存储持久卷)。

在所有准备加入的 Agent 节点上,提前执行以下命令:

# 在每个 Agent 节点上执行(通过 SSH)
apt update
apt install -y open-iscsi nfs-common

# 启动并设置开机自启
systemctl enable --now iscsid

执行加入命令

添加 Agent 节点的命令与添加 control-plane 节点几乎一致,但有两个关键区别:不使用 --server 标记且无需额外参数。

k3sup join \
--ip <AGENT_节点 IP> \
--user root \
--ssh-key <密钥位置> \
--server-ip <任意 Control 节点 IP> \
--k3s-channel latest

验证节点状态

可以一次性加入多个 Agent 节点。添加完成后等待几分钟,Cilium 与 Longhorn 的组件会自动调度到新节点。

使用 kubectl 查看集群状态:

kubectl get nodes -o wide

你应该能看到新加入的节点,其 ROLE 列显示为 <none>(在 k3s 中,<none> 即代表 agent/worker 角色)。 同时,你可以监控 Cilium 和 Longhorn 的 Pod 是否在新节点上成功启动:

# Cilium agent 应该会在新节点上启动
kubectl get pods -n kube-system -o wide

# Longhorn instance-manager 应该也会在新节点上启动
kubectl get pods -n longhorn-system -o wide

至此,集群已经拥有了高可用的控制平面和用于运行应用的工作节点。

下一步行动

  • 配置 Argo CD、Flux 等 GitOps 工具,将集群声明式管理流程标准化。
  • 部署 Prometheus、Loki、Grafana 等可观测性组件,完善监控与日志体系。
  • 使用 Ansible Playbook 自动化节点初始化与组件升级,降低后续运维成本。

参考资料